#include "item/circleitem.h"

#include <QStyleOptionGraphicsItem>
#include <QPainter>

namespace SymbolEditor
{

    GraphicsCircleItem::GraphicsCircleItem(GraphicsItem *parent):
        GraphicsItem(parent),
        m_radius(0.0)
    {
        addHandle(RadiusHandle, Handle::Role::Move, Handle::Shape::Diamond);
    }

    GraphicsCircleItem::~GraphicsCircleItem()
    {

    }

    qreal GraphicsCircleItem::radius() const
    {
        return m_radius;
    }

    void GraphicsCircleItem::setRadius(qreal length)
    {
        if (qFuzzyCompare(m_radius, length))
        {
            return;
        }

        prepareGeometryChange();
        m_radius = length;
        m_boundingRect = QRectF();
        update();

        blockItemNotification();
        m_idToHandle[RadiusHandle]->setPos(m_radius, 0);
        unblockItemNotification();
    }

    GraphicsItem *GraphicsCircleItem::clone()
    {
        GraphicsCircleItem *item = new GraphicsCircleItem();
        GraphicsItem::cloneTo(item);
        item->setRadius(radius());
        return item;
    }

    void GraphicsCircleItem::itemNotification(IObservableItem *item)
    {
        Handle *handle = static_cast<Handle *>(item);

        setRadius(qAbs(handle->pos().x()));
    }

    QList<PropertyId> GraphicsCircleItem::propertyIdList() const
    {
        auto result = GraphicsItem::propertyIdList();
        result << RadiusProperty;
        return result;
    }

    void GraphicsCircleItem::setProperty(PropertyId id, const QVariant &value)
    {
        switch (id)
        {
            case RadiusProperty:
                setRadius(value.toReal());
                break;
            default:
                GraphicsItem::setProperty(id, value);
                break;
        }
    }

    QVariant GraphicsCircleItem::property(PropertyId id) const
    {
        switch (id)
        {
            case RadiusProperty:
                return m_radius;
            default:
                return GraphicsItem::property(id);
        }
    }

    QList<QPointF> GraphicsCircleItem::endPoints() const
    {
        return QList<QPointF>();
    }

    QList<QPointF> GraphicsCircleItem::midPoints() const
    {
        return QList<QPointF>();
    }

    QList<QPointF> GraphicsCircleItem::centerPoints() const
    {
        return QList<QPointF>() << QPointF(0, 0);
    }

    QList<QPointF> GraphicsCircleItem::nearestPoints(QPointF pos) const
    {
        return QList<QPointF>() << nearestPoint(QPointF(0, 0), m_radius, mapFromScene(pos));
    }

    QRectF GraphicsCircleItem::boundingRect() const
    {
        if (m_boundingRect.isNull())
        {
            qreal pw = pen().style() == Qt::NoPen ? qreal(0) : pen().widthF();
            if (pw == 0.0 /*&& m_spanAngle == 360 * 16*/)
            {
                m_boundingRect.setWidth(2 * m_radius);
                m_boundingRect.setHeight(2 * m_radius);
            }
            else
            {
                m_boundingRect = shape().controlPointRect();
            }
        }

        return m_boundingRect;
    }

    QPainterPath GraphicsCircleItem::shape() const
    {
        QPainterPath path;
        path.addEllipse(QPointF(0, 0), m_radius, m_radius);
        return shapeFromPath(path, pen());
    }

    void GraphicsCircleItem::paint(QPainter *painter, const QStyleOptionGraphicsItem *option,
                                   QWidget *widget)
    {
        Q_UNUSED(widget);

        if (!shape().intersects(option->exposedRect))
        {
            return;
        }

        painter->setClipRect(option->exposedRect);
        painter->setPen(pen());
        painter->setBrush(brush());
        painter->drawEllipse(QPointF(0, 0), radius(), radius());
    }

    QVariant GraphicsCircleItem::itemChange(QGraphicsItem::GraphicsItemChange change,
                                            const QVariant &value)
    {
        if (change == QGraphicsItem::ItemSelectedHasChanged)
        {
            for (Handle *handle : m_handleToId.keys())
            {
                handle->setVisible(isSelected());
            }
        }
        return value;
    }

}
